package utils

import (
	"fmt"
	"reflect"
)

// SliceHas 利用Map判断指定值是否在Slice切片中存在
//
//	返回一个回调函数，用来判断值知否存在，结果为bool
//	基于泛型形参支持可比较类型，具体定义可参考泛型 comparable 接口
//	sl := []int{1,3,5,7,9}
//	f := SliceHas[int](sl)
//	f(2) // false
//	f(5) // true
func SliceHas[V comparable](s []V) func(V) bool {
	tmp := make(map[V]struct{}, len(s))
	for _, v := range s {
		tmp[v] = struct{}{}
	}
	return func(key V) bool {
		_, ok := tmp[key]
		return ok
	}
}

// SliceDelete 切片删除元素
func SliceDelete[V comparable](s []V, key V) []V {
	i := 0
	for _, v := range s {
		if v != key {
			s[i] = v
			i++
		}
	}
	return s[:i]
}

// SliceStructHas 利用Map判断指定字段值的结构体是否在Slice切片中存在
//
//	返回一个回调函数，用来判断指定字段值知否存在，结果为bool
//	基于泛型形参支持可比较类型，具体定义可参考泛型 comparable 接口
//	利用反射获取结构体指定字段，判断是否为可比较类型，并赋值给map的key
//	sl := []User{
//		{
//			Name:    "alpha",
//			Age:     20,
//			Sex:     "male",
//			Tickets: []string{"001", "002"},
//		},
//		{
//			Name:    "beta",
//			Age:     21,
//			Sex:     "female",
//			Tickets: []string{"003", "004"},
//		},
//	}
//	f := SliceStructHas[User, string](sl, "Name")
//	f("alpha") // true
//	f("sigma") // false
func SliceStructHas[V any, K comparable](s []V, key string) (func(K) bool, error) {
	tmp := make(map[K]V, len(s))
	for _, v := range s {
		of := reflect.ValueOf(v)
		f := of.FieldByName(key)
		if !f.Type().Comparable() {
			return nil, fmt.Errorf("key [%s] is not comparable type", key)
		}
		k := f.Interface().(K)
		tmp[k] = v
	}
	return func(key K) bool {
		_, ok := tmp[key]
		return ok
	}, nil
}

// SliceStructPop 查找切片中指定字段值的结构体并返回一个新数组
func SliceStructPop[V any, K comparable](s []V, key string, val K) ([]V, error) {
	tmp := make([]V, len(s))
	for _, v := range s {
		of := reflect.ValueOf(v)
		f := of.FieldByName(key)
		if !f.Type().Comparable() {
			return nil, fmt.Errorf("key [%s] is not comparable type", key)
		}
		k := f.Interface().(K)
		if k == val {
			tmp = append(tmp, v)
		}
	}
	return tmp, nil
}

// SliceStructDelete 删除切片中指定字段值的结构体并返回
func SliceStructDelete[V any, K comparable](s []V, key string, val K) ([]V, error) {
	i := 0
	for _, v := range s {
		of := reflect.ValueOf(v)
		f := of.FieldByName(key)
		if !f.Type().Comparable() {
			return nil, fmt.Errorf("key [%s] is not comparable type", key)
		}
		k := f.Interface().(K)
		if k != val {
			s[i] = v
			i++
		}
	}
	return s[:i], nil
}

// SliceIntersection 查找两个切片的交集
func SliceIntersection[V comparable](arr1 []V, arr2 []V) []V {
	seen := make(map[V]bool)
	for _, str := range arr1 {
		seen[str] = true
	}

	var intersection []V
	for _, str := range arr2 {
		if seen[str] {
			intersection = append(intersection, str)
		}
	}
	return intersection
}
